package com.broada.apm.logic.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.base.BaseLogic;
import com.broada.apm.cache.AlertSevertiyManager;
import com.broada.apm.entity.Alarm;
import com.broada.apm.entity.AlertSeverity;
import com.broada.apm.entity.NoticeCommandException;
import com.broada.apm.logic.AlertLogic;
import com.broada.apm.model.Alert;
import com.broada.apm.model.ConfigItem;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.Service;
import com.broada.apm.model.Threshold;
import com.broada.apm.model.ThresholdParam;
import com.broada.apm.service.internal.IndicatorService;
import com.broada.apm.service.internal.impl.IndicatorServiceImpl;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.JsonUtil;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

public class AlertLogicImpl extends BaseLogic implements AlertLogic {
	private Logger log = LoggerFactory.getLogger(AlertLogicImpl.class);
	private final String ALERT_THRESHOLD_CONFIG = "alert.threshold.config";
	private final String ALERT_ALGORITHM_CONFIG = "alert.algorithm.config";
	private IndicatorService indicatorService = new IndicatorServiceImpl();

	@Override
	public PagingList<Alarm> queryAlert(int severity, String alertType,
			Date startTime, Date endTime, String source, int status,
			int clearStatus, String keyWord, String sortField, String sortBy,
			int pageIndex, int pageSize) {
		Alert alert = new Alert();  // alert对象默认status = 0，clear_status = 0
		if (severity != 0)
			alert.setSeverity(severity);
		if (!StringUtils.isEmpty(alertType))
			alert.setType(alertType);
		if (!StringUtils.isEmpty(source))
			alert.setSource(source);
		// -1表示全部
		alert.setStatus(status);
		// -1表示全部
		alert.setClearStatus(clearStatus);
		
		if (!StringUtils.isEmpty(keyWord))
			alert.setDesc(keyWord);
		
		List<Alarm> alarms = Lists.newArrayList();
		PagingList<Alert> list = alertService.getAlert(alert, pageIndex, pageSize, startTime, endTime, sortField, sortBy);

		alarms = Lists.transform(list.getData(), new Function<com.broada.apm.model.Alert, Alarm>() {
			@Override
			public Alarm apply(com.broada.apm.model.Alert input) {
				return Alarm.wrap(input);
			}
		});
		PagingList<Alarm> pageList = new PagingList<Alarm>();
		pageList.setData(alarms);
		pageList.setPageSize(list.getPageSize());
		pageList.setStartPage(list.getStartPage());
		pageList.setTotalPages(list.getTotalPages());
		pageList.setTotalRecords(list.getTotalRecords());
		return pageList;
	}

	@Override
	public void deleteAlertById(String... ids) {
		for (String id : ids) {
			Alert alert = new Alert();
			alert.setId(id);
			alertService.deleteAlert(alert);
		}
	}

	@Override
	public void deleteAlert(Alert alert) {
		alertService.deleteAlert(alert);
	}

	@Override
	public void updateAlertStatus(int status, String... ids) {
		if (status == 2) {
			for(String id : ids) {
				Alert alert = alertService.getAlertById(id);
				alert.setStatus(status);
				alert.setClearStatus(1);
				alertService.updateAlert(alert);
			}
		} else {
			for(String id : ids) {
				Alert alert = alertService.getAlertById(id);
				alert.setStatus(status);
				alertService.updateAlert(alert);
			}
		}
	}

	@Override
	public List<Map<String, Object>> queryAlertStaticBySeverity() {
		List<Map<String, Object>> listResult = new ArrayList<Map<String, Object>>();
		try {
			List<AlertSeverity> severtiys = queryAlertSeverity();
			for (AlertSeverity severtiy : severtiys) {
				Map<String, Object> alertNumsMap = new HashMap<String, Object>();
				alertNumsMap.put("alarmCode", severtiy.getCode());
				alertNumsMap.put("alarmType", severtiy.getName());
				int count = alertService.getAlertCountBySeverity(severtiy.getCode());// 未处理的, 所有的，没有时间限制的某一级别的所有告警数
				alertNumsMap.put("alarmNum", count);
				listResult.add(alertNumsMap);
			}
		} catch (Exception e) {
			log.error("queryAlertStaticBySeverity告警等级个数统计失败:", e);
		}

		return listResult;
	}

	@Override
	public int queryAlertCountByWorstSeverity() {
		try {
			List<AlertSeverity> severtiys = queryAlertSeverity();
			for (AlertSeverity severtiy : severtiys) {
				int code = severtiy.getCode();
				int count = alertService.getAlertCountBySeverity(code);
				if(count != 0)
					return count;
			}
		} catch (Exception e) {
			log.error("queryAlertCountByWorstSeverity告警个数统计失败:", e);
		}
		return 0;
	}

	@Override
	public List<AlertSeverity> queryAlertSeverity() {
		List<AlertSeverity> severitys = new ArrayList<AlertSeverity>();
		Collection<AlertSeverity> items = AlertSevertiyManager.getInstance().getItems();
		Iterator<AlertSeverity> it = items.iterator();
		while (it.hasNext()) {
			AlertSeverity severity = (AlertSeverity) it.next();
			severitys.add(severity);
		}
		return severitys;
	}

	@Override
	public List<Alarm> queryAlertByType(String appId, String id, String type,
			int rows, String keyWord, String panelId, Date startDate, Date endDate, int severity) {
		List<Alarm> alarms = Lists.newArrayList();
		
		Alert alert = new Alert();
		alert.setApplicationId(appId);
		// 节点详情下，该节点下的交易类型告警也包括在内
		if (StringUtils.equalsIgnoreCase(type, "service")) {
			alert.setServiceId(id);
//			alert.setResourceId(null);
		}
		if (StringUtils.equalsIgnoreCase(type, "resource")) {
			alert.setResourceId(id);
		}
		if (StringUtils.isNotBlank(keyWord)) {
			alert.setDesc(keyWord);
		}
		if ("business".equals(panelId)) {
			alert.setType("business");
		} else if ("system".equals(panelId)) {
			alert.setType("system");
		}
		alert.setStatus(0);
		alert.setClearStatus(0);
		alert.setSeverity(severity);
		
		try {
			PagingList<Alert> list = alertService.getAlert(alert, 0, rows, startDate, endDate, null, null);

			alarms = Lists.transform(list.getData(), new Function<com.broada.apm.model.Alert, Alarm>() {
				@Override
				public Alarm apply(com.broada.apm.model.Alert input) {
					return Alarm.wrap(input);
				}
			});
			// 索引不存在不做任何处理
		} catch (Exception e) {
			ExceptionUtils.error(log, "queryAlertByType告警查询统计失败:", e);
		}
		return alarms;
	}

	@Override
	public boolean saveThreshold(String appId, Threshold threshold, String panelId) {
		try {
			String targetId = threshold.getTargetId();
			String id = null;
			if ("threshold".equals(threshold.getThresholdType())) {
				id = Joiner.on(".").join(ALERT_THRESHOLD_CONFIG, appId, targetId);
			} else {
				id = Joiner.on(".").join(ALERT_ALGORITHM_CONFIG, appId, targetId, panelId);
			}
			ConfigItem item = new ConfigItem(id, JsonUtil.obj2json(threshold));
			alertService.saveAlertThreshold(item);
			indicatorService.NoticeAlertRule("add", "thresholdconfig", appId, targetId, threshold.getThresholdType(), panelId);
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			return false;
		} catch (Exception e) {
			ExceptionUtils.error(log, e.getMessage(), e);
			return false;
		}
		return true;
	}

	@Override
	public com.broada.apm.entity.Threshold queryThresholdByTargetId(
			String appId, String targetId, String thresholdType, String panelId) {
		try {
			String id = Joiner.on(".").join(ALERT_THRESHOLD_CONFIG, appId, targetId);
			if ("algorithm".equals(thresholdType)) {
				id = Joiner.on(".").join(ALERT_ALGORITHM_CONFIG, appId, targetId, panelId);
			}
			ConfigItem item = alertService.getAlertThreshold(id);
			if (item != null)
				return (com.broada.apm.entity.Threshold) JsonUtil.json2obj(item.getValue(),
						com.broada.apm.entity.Threshold.class);
		} catch (Exception e) {
			ExceptionUtils.error(log, e.getMessage(), e);
		}
		return null;
	}

	@Override
	public List<com.broada.apm.entity.Threshold> queryThresholdsByApplicationId(
			String appId, String panelId) {
		List<com.broada.apm.entity.Threshold> thresholds = Lists.newArrayList();
		try {
			List<ConfigItem> items = alertService.getAlertThresholdLikeKey(Joiner.on(".").join(ALERT_THRESHOLD_CONFIG, appId) + ".");
			if (items != null) {
				for (ConfigItem item : items) {
					com.broada.apm.entity.Threshold threshold = (com.broada.apm.entity.Threshold) JsonUtil.json2obj(item.getValue(),
							com.broada.apm.entity.Threshold.class);
					List<ThresholdParam> list = new ArrayList<ThresholdParam>();
					for (ThresholdParam param : threshold.getThresholdParam()) {
						if ((param.getIndicator().startsWith("b") && "business".equals(panelId)) || (!param.getIndicator().startsWith("b") && "system".equals(panelId))) {
							list.add(param);
						}
					}
					
					if (!list.isEmpty()) {
						ThresholdParam[] thresholdParam = new ThresholdParam[list.size()];
						for (int i = 0; i < list.size(); i++) {
							thresholdParam[i] = list.get(i);
						}
						threshold.setThresholdParam(thresholdParam);
						thresholds.add(threshold);
					}
				}
			}
			items = alertService.getAlertThresholdLikeKey(Joiner.on(".").join(ALERT_ALGORITHM_CONFIG, appId) + ".");
			if (items != null) {
				for (ConfigItem item : items) {
					com.broada.apm.entity.Threshold threshold = (com.broada.apm.entity.Threshold) JsonUtil.json2obj(item.getValue(),
							com.broada.apm.entity.Threshold.class);
					if (panelId.equals(threshold.getPanelId())) {
						thresholds.add(threshold);
					}
				}
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, e.getMessage(), e);
		}
		return thresholds;
	}

	@Override
	public boolean deleteThresholdsByTargetId(String appId, String targetId, String thresholdType, String panelId) {
		try {
			if ("threshold".equals(thresholdType)) {
				alertService.deleteAlertThreshold(Joiner.on(".").join(ALERT_THRESHOLD_CONFIG, appId, targetId));
			} else {
				alertService.deleteAlertThreshold(Joiner.on(".").join(ALERT_ALGORITHM_CONFIG, appId, targetId, panelId));
			}
			indicatorService.NoticeAlertRule("remove", "thresholdconfig", appId, targetId, thresholdType, panelId);
		} catch (Exception e) {
			ExceptionUtils.error(log, e.getMessage(), e);
			return false;
		}
		return true;
	}

	@Override
	public List<Map<String, Object>> queryServerCountBySeverity() throws Exception {
		List<Map<String, Object>> listResult = new ArrayList<Map<String, Object>>();
		List<AlertSeverity> severtiys = queryAlertSeverity();
		for (AlertSeverity severtiy : severtiys) {
			Map<String, Object> serverNumsMap = new HashMap<String, Object>();
			serverNumsMap.put("alarmCode", severtiy.getCode());
			serverNumsMap.put("alarmType", severtiy.getName());
			Alert newAlert = new Alert();
			newAlert.setSeverity(severtiy.getCode());
			// 不论是已恢复或新告警都包含在内，但已处理的不包含在内
			newAlert.setClearStatus(0);
			newAlert.setStatus(0);
			List<Alert> alarms = Lists.newArrayList();
			PagingList<Alert> list = alertService.getAlert(newAlert, 0, Integer.MAX_VALUE, null, null, null, null);
			alarms = list.isEmpty() ? alarms : list.getData();
			Set<String> servIdSet = new HashSet<String>();
			for (Alert alert : alarms) {
				if ("default".equals(alert.getApplicationId())) {
					Service service = serviceService.getDisServiceById(alert.getServiceId());
					if (service != null && service.getFocus() == 1) {
						servIdSet.add(alert.getServiceId());
					}
				}
			}
			
			serverNumsMap.put("serverCount", servIdSet.size());
			listResult.add(serverNumsMap);
		}

		return listResult;
	}

	@Override
	public Integer queryAppAlertCount(String appId, Date startTime, Date endTime) {
		return alertService.getAppAlertCount(appId, startTime, endTime);
	}

	@Override
	public Map<String, Map<String, Object>> queryAlertByServiceAndSeverity(List<String> servIdList, Date startTime, Date endTime, int severity) {
		Map<String, Map<String, Object>> severityMap = alertService.getAlertByServiceAndSeverity(servIdList, startTime, endTime, severity);// 未处理的, 所有的，没有时间限制的某一级别的所有告警数
		return severityMap;
	}

	@Override
	public Map<String, Map<String, String>> queryAlertCountBySeverity(String groupBy, Date startTime, Date endTime) {
		Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
		Map<String, Map<String, Long>> severityMap = alertService.getAlertCountBySeverity(groupBy, startTime, endTime);// 未处理的, 所有的，没有时间限制的某一级别的所有告警数
		for (String key : severityMap.keySet()) {
			Map<String, String> subMap = map.get(key.substring(0, key.lastIndexOf("-")));
			if (subMap == null) {
				subMap = new HashMap<String, String>();
				subMap.put(key.substring(key.lastIndexOf("-") + 1) + "Count", severityMap.get(key).get("num").toString());
				map.put(key.substring(0, key.lastIndexOf("-")), subMap);
			} else {
				subMap.put(key.substring(key.lastIndexOf("-") + 1) + "Count", severityMap.get(key).get("num").toString());
			}
		}
		return map;
	}

	@Override
	public Map<String, Map<String, String>> queryAlertCountByType(String type, Date startTime, Date endTime) {
		Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
		Map<String, Map<String, Long>> severityMap = alertService.getAlertCountByType(type, startTime, endTime);// 未处理的, 所有的，没有时间限制的某一级别的所有告警数
		for (String key : severityMap.keySet()) {
			Map<String, String> subMap = map.get(key.substring(0, key.lastIndexOf("-")));
			if (subMap == null) {
				subMap = new HashMap<String, String>();
				if ("rpm".equals(key.substring(key.lastIndexOf("-") + 1)) || "lrpm".equals(key.substring(key.lastIndexOf("-") + 1))) {
					subMap.put("rpmCount", (Integer.parseInt(severityMap.get(key).get("num").toString()) + Integer.parseInt(subMap.get("rpmCount") == null ? "0" : subMap.get("rpmCount"))) + "");
				} else if ("brpm".equals(key.substring(key.lastIndexOf("-") + 1)) || "blrpm".equals(key.substring(key.lastIndexOf("-") + 1))) {
					subMap.put("brpmCount", (Integer.parseInt(severityMap.get(key).get("num").toString()) + Integer.parseInt(subMap.get("brpmCount") == null ? "0" : subMap.get("brpmCount"))) + "");
				} else {
					subMap.put(key.substring(key.lastIndexOf("-") + 1) + "Count", severityMap.get(key).get("num").toString());
				}
				map.put(key.substring(0, key.lastIndexOf("-")), subMap);
			} else {
				if ("rpm".equals(key.substring(key.lastIndexOf("-") + 1)) || "lrpm".equals(key.substring(key.lastIndexOf("-") + 1))) {
					subMap.put("rpmCount", (Integer.parseInt(severityMap.get(key).get("num").toString()) + Integer.parseInt(subMap.get("rpmCount") == null ? "0" : subMap.get("rpmCount"))) + "");
				} else if ("brpm".equals(key.substring(key.lastIndexOf("-") + 1)) || "blrpm".equals(key.substring(key.lastIndexOf("-") + 1))) {
					subMap.put("brpmCount", (Integer.parseInt(severityMap.get(key).get("num").toString()) + Integer.parseInt(subMap.get("brpmCount") == null ? "0" : subMap.get("brpmCount"))) + "");
				} else {
					subMap.put(key.substring(key.lastIndexOf("-") + 1) + "Count", severityMap.get(key).get("num").toString());
				}
			}
		}
		return map;
	}

}
